﻿#region copyright
//  Copyright (C) 2022 Auto Dark Mode
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
#endregion
using System;
using System.Linq;

namespace AutoDarkModeSvc.Communication;

public static class Address
{
    public const string PipePrefix = "admpipe";
    public const string PipeResponse = "_response";
    public static string PipeRequest { get; } = $"_request_{Environment.UserName.ToLower()}";
    public const string DefaultPort = "54345";
}
public static class Command
{
    /// <summary>
    /// Invokes a theme switch based on time. Only returns an ApiResponse with StatusCode.Ok or a StatusCode.Timeout
    /// </summary>
    [Includable]
    public const string RequestSwitch = "--switch";

    /// <summary>
    /// Basically useless currently, needs rework
    /// </summary>
    [Includable]
    public const string Swap = "--swap";

    /// <summary>
    /// Requests Auto Dark Mode to switch to the light theme and pauses 
    /// switching once. Only returns an ApiResponse with StatusCode.Ok or a StatusCode.Timeout
    /// </summary>
    [Includable]
    public const string Light = "--light";

    /// <summary>
    /// Requests Auto Dark Mode to switch to the dark theme. Only returns an ApiResponse with StatusCode.Ok or a StatusCode.Timeout
    /// </summary>
    [Includable]
    public const string Dark = "--dark";

    /// <summary>
    /// Forces light theme and sets the GlobalState force flag. Only returns an ApiResponse with StatusCode.Ok or a StatusCode.Timeout
    /// </summary>
    [Includable]
    public const string ForceLight = "--force-light";

    /// <summary>
    /// Forces dark theme and sets the GlobalState force flag. Only returns an ApiResponse with StatusCode.Ok or a StatusCode.Timeout
    /// </summary>
    [Includable]
    public const string ForceDark = "--force-dark";

    /// <summary>
    /// Resets the GlobalState force theme flag. Only returns an ApiResponse with StatusCode.Ok or a StatusCode.Timeout
    /// </summary>
    [Includable]
    public const string NoForce = "--no-force";


    /// <summary>
    /// Delays the theme switch by a user set amount passed as additional parameter in minnutes 
    /// Returns an APIResponse with StatusCode.Ok, StatusCode.Err if parameter is invalid or a StatusCode.Timeout
    /// </summary>
    [Includable]
    public const string DelayBy = "--delay-by";

    /// <summary>
    /// Toggles skipping the next pending theme switch off or on
    /// Returns an APIResponse with StatusCode.Ok or a StatusCode.Timeout 
    /// and a message with true or false to indicate whether skipping is enabled or disabled
    /// </summary>
    [Includable]
    public const string ToggleSkipNext = "--toggle-skip-next";

    [Includable]
    public const string ClearPostponeQueue = "--clear-postpone-queue";

    [Includable]
    public const string GetPostponeStatus = "--get-postpone-status";

    /// <summary>
    /// Returns the internal theme that ADM is currently maintaining
    /// </summary>
    [Includable]
    public const string GetRequestedTheme = "--get-requested-theme";

    /// <summary>
    /// Returns the current system colorization color (accent color)
    /// Returns a hex string of the last parsed colorization color and the currently requested theme as details
    /// </summary>
    [Includable]
    public const string GetCurrentColorization = "--get-colorization";

    /// <summary>
    /// Checks for updates silently
    /// ApiResponse with StatusCode.New if an update is available, <br/>
    /// StatusCode.Ok if no update is available <br/>
    /// StatusCode.Err if an error has occurred. <br/>
    /// Message carries the current version string <br/>
    /// Details carries a yaml serialized UpdateInfo object</summary>
    [Includable]
    public const string CheckForUpdate = "--check-for-update";

    /// <summary>
    /// Checks for updates loudly (shows toast message)
    /// ApiResponse object as string with StatusCode.New if an update is available, <br/>
    /// StatusCode.Ok if no update is available <br/>
    /// StatusCode.Err if an error has occurred. <br/>
    /// StatusCode.UnsupportedOperation if ADM has been installed in all users mode <br/>
    /// StatusCode.Disabled if a manual update is required
    /// Message carries the current version string <br/>
    /// Details carries a yaml serialized UpdateInfo object</summary>
    [Includable]
    public const string CheckForUpdateNotify = "--check-for-update-notify";

    [Includable]
    public const string CheckForDowngradeNotify = "--check-for-downgrade-notify";

    /// <summary>
    /// Invokes an update. this requires that CheckForUpdate has been run beforehand
    /// Returns an ApiResponse object as string with StatusCode.New if an update can be performed, <br/>
    /// StatusCode.UnsupportedOperation if ADM has been installed in all users mode <br/>
    /// StatusCode.Disabled if a manual update is required
    /// Returns any other status code if the update was not possible.
    /// </summary>
    [Includable]
    public const string Update = "--update";

    /// <summary>
    /// Checks if locationAccess is available <br/>
    /// Returns an ApiResponse object as string with
    /// StatusCode.Ok if everything is well
    /// Statuscode.Err if an error has occurred, and a message if it is a regkey or task scheduler issue
    /// </summary>
    public const string LocationAccess = "--location-access";

    /// <summary>
    /// Checks if the geolocator is currently updating <br/>
    /// Returns an ApiResponse object as string with
    /// StatusCode.Ok if the locator is not updating
    /// StatusCode.InProgress if the geolocator is currently updating
    /// </summary>
    [Includable]
    public const string GeolocatorIsUpdating = "--geolocator-is-updating";

    [Includable]
    public const string AddAutostart = "--add-autostart";

    [Includable]
    public const string RemoveAutostart = "--remove-autostart";

    [Includable]
    public const string GetAutostartState = "--get-autostart-state";

    [Includable]
    public const string ValidateAutostart = "--validate-autostart";

    [Includable]
    public const string Shutdown = "--exit";

    [Includable]
    public const string Restart = "--restart";

    [Includable]
    public const string Alive = "--alive";

    [Includable]
    public const string DetectMonitors = "--detect-monitors";

    [Includable]
    public const string CleanMonitors = "--clean-monitors";

    public const string UpdateFailed = "--update-failed";

    public const string GetLearnedThemeNames = "--get-learned-theme-names";

    [Includable]
    public const string Test = "--test";

    [Includable]
    public const string Test2 = "--test2";

    public const string TestError = "--test-error";

    public const string TestNotifications = "--test-notifications";

    public const string TestNotifications2 = "--test-notifications2";
}

[AttributeUsage(AttributeTargets.Field)]
public class IncludableAttribute : Attribute
{
}

public static class StatusCode
{
    public static string Available { get; } = "Available";
    public static string New { get; } = "New";
    public static string Downgrade { get; } = "Downgrade";
    public static string NoLocAccess { get; } = "NoLocAccess";
    public static string Err { get; } = "Err";
    public static string Ok { get; } = "Ok";
    public static string Timeout { get; } = "Timeout";
    public static string UnsupportedOperation { get; } = "UnsupportedOperation";
    public static string No { get; } = "No";
    public static string Disabled { get; } = "Disabled";
    public static string InProgress { get; } = "InProgress";
    public static string AutostartTask { get; } = "AutostartTask";
    public static string AutostartRegistryEntry { get; } = "AutostartRegistryEntry";
    public static string Modified { get; } = "Modified";
}

public class ApiResponse
{
    public const string separator = "\nAdmApiDataRow=";
    public string StatusCode { get; set; }
    public string Message { get; set; }
    public string Details { get; set; }

    public override string ToString()
    {
        return StatusCode != null && StatusCode.Length > 0
            ? Message != null && Message.Length > 0
            ? Details != null && Details.Length > 0
            ? $"{StatusCode}{separator}{Message}{separator}{Details}"
            : $"{StatusCode}{separator}{Message}"
            : $"{StatusCode}"
            : "";
    }

    public static ApiResponse FromString(string response)
    {
        try
        {
            string[] responseSplit = response.Split(separator);
            return new ApiResponse
            {
                StatusCode = responseSplit.ElementAtOrDefault(0),
                Message = responseSplit.ElementAtOrDefault(1),
                Details = responseSplit.ElementAtOrDefault(2),
            };
        }
        catch (Exception ex)
        {
            return new ApiResponse
            {
                StatusCode = Communication.StatusCode.Err,
                Message = ex.Message
            };
        }
    }
}